library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity SF_FIFO_monitor is
  port( 							-- Signals internal to switch fabric
    clk, reset: in std_logic;
    send_L: in std_logic;			--hold, 
    ODL_emp: in std_logic_vector(2 downto 0); 
    i_O_FIFO: in std_logic_vector(3 downto 0); --input from 3 (now 4) bit output FIFO
    i_L_FIFO: in std_logic_vector(11 downto 0);
    o_L_FIFO: out std_logic_vector(11 downto 0);
    o_read_O, o_read_L, o_read_D: out std_logic;
    xfer_D_req, xfer_L_req: out std_logic_vector(3 downto 0)
  );  
end SF_FIFO_monitor;
-----------------------------------------------------------
architecture multi_state_controller of SF_FIFO_monitor is 
	

	type register_state is
		(idle, load_data, send_data); 
	signal CS, NS: register_state;
	signal s_o_read_L, s_o_read_O: std_logic;
	signal NS_FIFO, CS_FIFO: std_logic_vector(3 downto 0); --Signals holding the Output port info
	signal NS_Length, CS_Length: std_logic_vector(11 downto 0);
begin
--control path: state register
	process(clk, reset)
	begin
		if reset = '1' then CS <= idle;
		elsif (clk'event and clk = '1') then 
			CS <= NS;
			CS_FIFO <= NS_FIFO;
			CS_Length <= NS_Length;
		end if; 														
	end process; 		
-- next state logic

    process(CS, CS_FIFO, i_O_FIFO, i_L_FIFO, CS_Length)
	begin
		if(CS=idle) then
			 NS_FIFO <= "1000";
			 NS_Length <= "000000000000";
		elsif(CS=load_data) then
			 NS_FIFO 	<= i_O_FIFO;
			 NS_Length 	<= i_L_FIFO;
		else NS_FIFO 	<= CS_FIFO; 
			 NS_Length	<= CS_Length;
		end if;
	end process;


PROCESS(CS, NS, ODL_emp, send_L, i_O_FIFO, clk, reset)  --hold, 
begin  
    case CS is
		when idle =>                                   
			if ODL_emp = "000" then NS <= load_data;  		                
			else  NS <= idle;
			end if; 
        when load_data =>   
            if reset = '0' then 
				NS <= send_data; 
			else
				NS <= idle;
			end if;
            
		when send_data =>
			if send_L = '1' then NS <= idle;
			else NS <= send_data;
			end if;	 
    end case; 
  end process;
  
-- output logic
process(clk, CS, send_L, CS_FIFO)		--, s_FIFO_O,
begin 
	case CS is
		when idle =>
			s_o_read_L 	<= '0';
			s_o_read_O 	<= '0';
			o_read_D 	<= '0';
			xfer_D_req <= "0000";
			xfer_L_req <= "0000";			

		
		when load_data =>
		  	s_o_read_L 	<= '1';
			s_o_read_O 	<= '1';
			o_read_D 	<= '0';
			xfer_D_req 	<= "0000";
			xfer_L_req 	<= "0000";									
		when send_data =>
			o_read_D 	<= '1';
			s_o_read_O 	<= '0';
			s_o_read_L 	<= '0';
			
			case CS_FIFO is 
				when "0000" =>
					xfer_D_req<="0001";  --send high signal to xmt port 0
					xfer_L_req<="0001";
				when "0001" =>
					xfer_D_req<="0010";	 --send high signal to xmt port 1
					xfer_L_req<="0010";
				when "0010" =>
					xfer_D_req<="0100";	 --send high signal to xmt port 2
					xfer_L_req<="0100";
				when "0011" =>
					xfer_D_req<="1000";  --send high signal to xmt port 3
					xfer_L_req<="1000";
				when "0100" =>
					xfer_D_req<="1110";  -- send high signal to xmt ports 1,2,3
					xfer_L_req<="1110";
				when "0101" =>
					xfer_D_req<="1101";  -- send high signal to xmt ports 0,2,3
					xfer_L_req<="1101";
				when "0110" =>
					xfer_D_req<="1011";  -- send high signal to xmt ports 0,1,3
					xfer_L_req<="1011";
				when "0111" =>
					xfer_D_req<="0111";  -- send high signal to xmt ports 0,1,2
					xfer_L_req<="0111";
				when others =>
					xfer_D_req<="0000";  -- assert low signal for all xmt ports (dropping packet)
					xfer_L_req<="0000";									
			end case;		
	end case;
	end process;
	
o_L_FIFO 	<=  CS_Length;	
o_read_L	<=	s_o_read_L; 
o_read_O	<=	s_o_read_O;

end multi_state_controller;        